package com.tplhk.security.config;//package com.tplhk.security.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.io.PrintWriter;

/**
 * @ClassName : SecurityConfig
 * @Description : TODO
 * @Author : taiping
 * @Date: 2021/6/22 17:24
 **/
@Configuration
public class SecurityConfigCharter12 extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailsService userService;

    @Autowired
    AccessDeniedHandlerExt accessDeniedHandlerExt;

    @Autowired
    AuthenticationEntryPointExt authenticationEntryPointExt;

    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
//      配置用户信息方式 3 , 从数据库中读取用户
        auth.userDetailsService(userService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // --------------1. 配置所有请求都要鉴权
        http.authorizeRequests()
//                ------------1.1 配置以下不同的 url 需要不同的角色
//                ------** 表示多层，* 表示一层， ?表示单个字符
                .antMatchers("/v12/admin/**").hasAnyAuthority("admin")
                .antMatchers("/v12/user/**").hasAnyAuthority("user")
//                --------------1.2 anyRequest 必须放在最后面！！
//                注意顺序，上往下的顺序来匹配，一旦匹配到了就不继续匹配了
                .anyRequest()
                .authenticated()
                .and()
                // -----------2. 配置登陆请求
                .formLogin()
//                -----2.1 定义请求账密的参数
                .usernameParameter("username")
                .passwordParameter("password")
//                --------2.2 请求接口, 不需要在 controller 中实现:
//                http://localhost:8082/v1/hello/login?username=javaboy.org&password=123
                .loginPage("/v1/login")
//                --------2.3 请求成功后返回字符串给前端
                .successHandler((req, resp, authentication) -> {
                    Object principal = authentication.getPrincipal();
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write(new ObjectMapper().writeValueAsString(principal));
                    out.flush();
                    out.close();
                })
//                --------2.4 请求失败后返回字符串给前端
                .failureHandler((req, resp, e) -> {
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write(e.getMessage());
                    out.flush();
                    out.close();
                })
//                ------2.5 对于 /v1/hello/login 地址不鉴权: http://localhost:8082/logout
                .permitAll()
                .and()
//             3. 配置退出请求接口
                .logout()
//                -------------3.1 成功退出，返回字符串给前端
                .logoutSuccessHandler((req, resp, authentication) -> {
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write("注销成功");
                    out.flush();
                    out.close();
                })
//                ----------3.2 对于 /logout 地址不鉴权
                .permitAll()
                .and()
//                rememberMe 功能没有在 postman 上测试，待验证
                .rememberMe()
//                ---- 下面的key 设置为固定的，默认情况是随机uuid， 否则服务端重启后，rememberMe 会失效
                .key("setKey")
                .and()
                .csrf().disable()
                // 4. 未登陆时访问其它地址时，返回字符串给前端 : http://localhost:8082/v1/hello/hello
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPointExt)
                .accessDeniedHandler(accessDeniedHandlerExt)
        ;
    }


}
